package pufsim

import chisel3._
import chisel3.util._
import chisel3.experimental._

import uart2._
import puf2._ 
import top._


class top extends Module{
    val io = IO(new Bundle{
        val puf_out     =   new PUF_Top_Output_Ports     
    })

    val M_puf           =   Module(new puf_top)
    val M_control       =   Module(new control)

    val rst_n           =   Wire(Reset())
    rst_n               :=  Mux(reset.asBool, false.B, true.B)

//  __    __       ___      .______     .___________.      .___________.___   ___ 
// |  |  |  |     /   \     |   _  \    |           |      |           |\  \ /  / 
// |  |  |  |    /  ^  \    |  |_)  |   `---|  |----`______`---|  |----` \  V  /  
// |  |  |  |   /  /_\  \   |      /        |  |    |______|   |  |       >   <   
// |  `--'  |  /  _____  \  |  |\  \----.   |  |               |  |      /  .  \  
//  \______/  /__/     \__\ | _| `._____|   |__|               |__|     /__/ \__\ 
                                                                               
    // input
    // M_uart_tx.io.clk            :=      clock 
    // M_uart_tx.io.rst_n          :=      rst_n
    // M_uart_tx.io.tx_data        :=      M_control.io.uart_tx_data
    // M_uart_tx.io.tx_data_valid  :=      M_control.io.uart_tx_valid
    // output
    // M_control.io.uart_tx_ready  :=      M_uart_tx.io.tx_data_ready
    // io.uart.uart_tx             :=      M_uart_tx.io.tx_pin

     M_control.io.uart_tx_ready  :=      true.B

//  __    __       ___      .______     .___________.      .______     ___   ___ 
// |  |  |  |     /   \     |   _  \    |           |      |   _  \    \  \ /  / 
// |  |  |  |    /  ^  \    |  |_)  |   `---|  |----`______|  |_)  |    \  V  /  
// |  |  |  |   /  /_\  \   |      /        |  |    |______|      /      >   <   
// |  `--'  |  /  _____  \  |  |\  \----.   |  |           |  |\  \----./  .  \  
//  \______/  /__/     \__\ | _| `._____|   |__|           | _| `._____/__/ \__\ 
                                                                              
    // input
    // M_uart_rx.io.clk            :=      clock 
    // M_uart_rx.io.rst_n          :=      rst_n
    // M_uart_rx.io.rx_data_ready  :=      M_control.io.uart_rx_ready
    // M_uart_rx.io.rx_pin         :=      io.uart.uart_rx
    // output
    // M_control.io.uart_rx_data   :=      M_uart_rx.io.rx_data
    // M_control.io.uart_rx_valid  :=      M_uart_rx.io.rx_data_valid

    // val rx_data                 :=      RegInit(0.U(8.W))
    // val rx_count                :=      RegInit(0.U(8.W))
    // rx_count                    :=      rx_count    +   1.U

    // when( rx_count  < 16.U ){
    //     rx_data :=  0.U
    // }
    // .elsewhen(rx_data === 16.U){
    //     rx_data :=  "h53".U
    // }
    // .elsewhen(rx_data > 16.U && rx_data < 100.U){
    //     rx_data :=  "hAA".U 
    // }.otherwise{
    //     rx_data :=  0.U
    // }
    
    
    val cnt_rx_data     =   RegInit(0.U(32.W))
    cnt_rx_data         :=  cnt_rx_data + 1.U

    val the_rx_data     =   Wire(UInt(8.W))
    
    val regs_data       =   Reg(Vec(29, UInt(8.W)))
    val cnt_regs_data   =   RegInit(0.U(8.W))

    when(cnt_regs_data <= 28.U ){
        cnt_regs_data   :=  cnt_regs_data   +   1.U 
    }.otherwise{
        cnt_regs_data    :=  0.U
    }

    when(reset.asBool){
        regs_data(0)        :=  "h53".U 
        for( i <- 1 until 28 ){
            regs_data(i)    :=  i.U 
        }
        regs_data(28)       :=  "hff".U 
    }
    
    when( cnt_rx_data < 80000.U || cnt_rx_data > 160000.U ){
        the_rx_data :=  regs_data(cnt_regs_data) // "h53".U 
    }.otherwise{
        the_rx_data :=  "hff".U 
    }

    M_control.io.uart_rx_data   :=      the_rx_data
    M_control.io.uart_rx_valid  :=      true.B 

// .______    __    __   _______ 
// |   _  \  |  |  |  | |   ____|
// |  |_)  | |  |  |  | |  |__   
// |   ___/  |  |  |  | |   __|  
// |  |      |  `--'  | |  |     
// | _|       \______/  |__|     

    M_puf.io.out                <>      io.puf_out
    M_puf.io.ctr.puf_in_valid   :=      M_control.io.puf_in_valid
    M_puf.io.ctr.puf_data_in    :=      M_control.io.puf_data_in
    M_puf.io.ctr.puf_out_ready  :=      M_control.io.puf_out_ready
    M_puf.io.ctr.puf_wl_ena     :=      M_control.io.puf_wl_ena 
    M_puf.io.ctr.puf_write_ena  :=      M_control.io.puf_write_ena

    M_control.io.puf_in_ready   :=      M_puf.io.ctr.puf_in_ready
    M_control.io.puf_out_valid  :=      M_puf.io.ctr.puf_out_valid
    M_control.io.puf_data_out   :=      M_puf.io.ctr.puf_data_out

    val cnt_data_out            =       RegInit(0.U(8.W))
    cnt_data_out                :=      cnt_data_out    +   1.U 
    
    val the_data_out            =       Wire(UInt(1.W))
    the_data_out                :=      cnt_data_out(7)

    M_puf.io.out.Data_out       :=      the_data_out
}